package com.ashraya.framework.dao;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * 
 * This will be our data access object framework implementation. This module
 * accesses the database using Hibernate.
 * <p>
 * Created on Feb 28, 2010
 * <p>
 * 
 * @author PankajK
 * 
 */
public abstract class CoreDaoImpl<T> extends HibernateDaoSupport implements CoreDao<T> {

	/**
	 * Saves the object to the database and returns a serializable object.
	 * 
	 * @param obj
	 * @return
	 * @throws DataAccessException
	 */
	public Serializable save(T obj) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		
		return template.save(obj);
	}

	/**
	 * Updates object to the database.
	 * 
	 * @param obj
	 * @throws DataAccessException
	 */
	public void update(T obj) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		template.update(obj);
	}

	/**
	 * Deletes object from the database.
	 * 
	 * @param obj
	 * @throws DataAccessException
	 */
	public void delete(T obj) throws DataAccessException {
		getHibernateTemplate().delete(obj);
	}

	/**
	 * Finds and returns an object in the database using class name and Integer
	 * primary key.
	 * 
	 * @param clazz
	 * @param pk
	 * @return
	 * @throws DataAccessException
	 */
	public T findByPK(Class<T> clazz, Integer pk) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		return template.get(clazz, pk);
	}

	/**
	 * Finds and returns an object in the database using class name and String
	 * primary key.
	 * 
	 * @param clazz
	 * @param pk
	 * @return
	 * @throws DataAccessException
	 */
	public T findByPK(Class<T> clazz, String pk) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		return template.get(clazz, pk);
	}

	/**
	 * Finds and returns a list of objects using class name.
	 * 
	 * @param clazz
	 * @return
	 * @throws DataAccessException
	 */
	public List<T> findAll(Class<T> clazz) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		return template.find("from " + clazz.getName());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.fbfs.cp.pic.framework.dao.CoreDao#findAll(java.lang.String)
	 */
	public List<T> findAll(String hql) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		return template.find(hql);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.fbfs.cp.pic.framework.dao.CoreDao#findByPK(java.lang.Class,
	 * java.lang.Short)
	 */
	public T findByPK(Class<T> clazz, Short pk) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		return template.get(clazz, pk);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.fbfs.cp.pic.framework.dao.CoreDao#findAll(java.lang.String,
	 * java.lang.Object[])
	 */
	public List<T> findAll(String hql, Object[] values) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		return template.find(hql, values);
	}

	public List<T> findAll(String hql, Object[] values, int maxResults) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		template.setMaxResults(maxResults);
		return template.find(hql, values);
	}

	public List<T> findAll(CoreCriteria<T> criteria) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		if (criteria.getFetchSize() > 0) {
			template.setMaxResults(criteria.getFetchSize());
		}
		DetachedCriteria detachedCriteria = criteria.getCriteria();
		List<T> result = template.findByCriteria(detachedCriteria);
		template.setMaxResults(0); // Set it again to default
		return result;
	}

	public List<T> cachedFindAll(CoreCriteria<T> coreCriteria) {
		Criteria criteria = coreCriteria.getCriteria().getExecutableCriteria(getSession());
		criteria.setCacheable(true);
		return criteria.list();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.fbfs.cp.pic.framework.dao.CoreDao#findAll(java.lang.String,
	 * java.util.List)
	 */
	public List<T> findAll(String hql, List values) throws DataAccessException {
		List<T> result = null;
		if (values == null || values.isEmpty()) {
			result = findAll(hql);
		} else {
			Object[] params = values.toArray();
			result = findAll(hql, params);
		}
		return result;
	}

	public List<T> findAll(String hql, List values, int maxResults) throws DataAccessException {
		List<T> result = null;
		if (values == null || values.isEmpty()) {
			result = findAll(hql);
		} else {
			Object[] params = values.toArray();
			result = findAll(hql, params, maxResults);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.fbfs.cp.pic.framework.dao.CoreDao#findAll(java.lang.Object)
	 */
	public List<T> findAll(T example) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		return template.findByExample(example);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.fbfs.cp.pic.framework.dao.CoreDao#saveOrUpdate(java.util.Collection)
	 */
	public void saveOrUpdate(Collection<T> col) throws DataAccessException {
		HibernateTemplate template = getHibernateTemplate();
		template.saveOrUpdateAll(col);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.fbfs.cp.pic.framework.dao.CoreDao#findAll(java.lang.String,
	 * java.lang.String[], java.lang.Object[])
	 */
	public List<T> findAll(String hql, String[] params, Object[] values) throws DataAccessException {
		List<T> result = getHibernateTemplate().findByNamedParam(hql, params, values);
		return result;
	}

	public List<T> cachedFindAll(String hql, String[] params, Object[] values) {
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			logger.info("setting parameter[" + params[i] + " ] =  " + values[i]);
			query.setParameter(params[i], values[i]);
		}
		query.setCacheable(true);

		return query.list();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.fbfs.cp.pic.framework.dao.CoreDao#findByNamedQuery(java.lang.String)
	 */
	public List<T> findByNamedQuery(String hql) {
		return getHibernateTemplate().findByNamedQuery(hql);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.fbfs.cp.pic.framework.dao.CoreDao#findByNamedQuery(java.lang.String,
	 * java.lang.Object[])
	 */
	public List<T> findByNamedQuery(String hql, Object[] values) {
		return getHibernateTemplate().findByNamedQuery(hql, values);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.fbfs.cp.pic.framework.dao.CoreDao#findByNamedQuery(java.lang.String,
	 * java.lang.String[], java.lang.Object[])
	 */
	public List<T> findByNamedQuery(String hql, String[] params, Object[] values) {
		return getHibernateTemplate().findByNamedQueryAndNamedParam(hql, params, values);
	}

	public void evict(Object obj) {
		getHibernateTemplate().evict(obj);
	}

	public void refresh(Object obj) {
		getHibernateTemplate().refresh(obj);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.fbfs.cp.pic.framework.dao.CoreDao#deleteAll(java.util.Collection)
	 */
	public void deleteAll(Collection<T> deleteItems) {
		getHibernateTemplate().deleteAll(deleteItems);
	}

	public void flush() {
		getHibernateTemplate().flush();
	}

	public T findFirst(CoreCriteria<T> criteria) throws DataAccessException {
		List<T> list = findAll(criteria);
		if (list.isEmpty())
			return null;
		return list.get(0);
	}

}
